package com.sleepingrain;


import java.util.Random;
import android.util.Log;

class WaveGenerator extends SoundGenerator
{
	private int mTime;
	private int mBackgroundTime;
	private Random mRnd;
	
	private int mIntensity;
	private int mWaveheight;
	private int mInterval;
	
	WaveGenerator(SoundBuffer sb,SampleLib lib)
	{
		super(sb,lib);
		mRnd = new Random();
	}
	
	public void setIntensity(int intensity)
	{
		mIntensity = intensity;
		m_soundBuffer.divisor = 10;
	}
	
	public void setWaveheight(int waveheight)
	{
		mWaveheight = waveheight;
		m_soundBuffer.divisor = 10;
	}
	
	public void setInterval(int interval)
	{
		mInterval = interval;
		m_soundBuffer.divisor = 10;
	}
	
	public int getIntensity()
	{
		return mIntensity;
	}
	
	public int getWaveheight()
	{
		return mWaveheight;
	}
	
	public int getInterval()
	{
		return mInterval;
	}
	
	/**
	 * Function to generate primary and background waves
	 */
	protected void generate()
	{
		Thread.currentThread().setName("WaveGenerator");
		generatePrimaryWave();
		generateBackgroundWaves();
	}
	
	/**
	 * Function to get a sample out of the sample library
	 * @return the sample
	 */
	protected Sample getSample()
	{
		int sampleIndex;
		Sample sample = null;
		
		do{
			// Select sample from the sample library
			sampleIndex = (int)Math.round(mRnd.nextGaussian() + (m_sampleLib.size()-1) / 100.0f * mWaveheight);
			if(sampleIndex <0){
				sampleIndex = Math.abs(sampleIndex);
			}
			if(sampleIndex >= m_sampleLib.size()){
				sampleIndex = sampleIndex -(sampleIndex-m_sampleLib.size()-1);
			}
			
			// Ensure the index is valid!
			sampleIndex = Math.max(Math.min(m_sampleLib.size()-1, sampleIndex),0);

			try{
				sample = m_sampleLib.get(sampleIndex);			
			}catch(IndexOutOfBoundsException ex){
				Log.d("WaveGenerator", "Illegal sampleIndex: "+ex);
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}while(sample == null);
		
		return sample;
	}
	
	/**
	 * Function to generate a primary wave and add it to the sound buffer
	 */
	void generatePrimaryWave()
	{
		// get the wave sample from the sample library
		Sample sample = getSample();

		// calculate the volume of the wave
		int volume = mRnd.nextInt(16)+60+mWaveheight/4;
		
		// insert the wave sample into the sound buffer
		mTime = m_soundBuffer.insertSample(this, 0, mTime, sample, 0, sample.sampleCount, volume);
		
		// calculate the length of the wave
		double rndInterval = 0.90 + mInterval/90.0 + mRnd.nextGaussian()/10.0;
		mTime += Math.round(rndInterval * sample.sampleCount);
	}

	/**
	 * Function to generate background waves an add them to the sound buffer
	 */
	void generateBackgroundWaves()
	{
		while(mBackgroundTime < mTime)
		{
			// get the wave sample from the sample library
			Sample sample = getSample();
			
			// calculate the volume of the wave
			int volume = mRnd.nextInt(5)+mWaveheight/5 + mIntensity/10;
			
			// insert the wave sample into the sound buffer
			m_soundBuffer.insertSample(this, 0, mBackgroundTime, sample, 0, sample.sampleCount, volume);
			Log.d("WaveTest", "Add secoundary Wave: "+mBackgroundTime + " Volume: "+volume);

			// calculate the length of the wave
			double rndInterval =  0.90 +(mRnd.nextGaussian()/10.0);
			mBackgroundTime += Math.round((rndInterval * sample.sampleCount)/(1.0f+mIntensity/25.0));
		}
	}
}


class SeaGullGenerator extends SoundGenerator
{
	private int mTime;
	private Random mRnd;
	private int mSeaGull;	
	
	SeaGullGenerator(SoundBuffer sb, SampleLib lib) {
		super(sb, lib);
		mRnd = new Random();
	}

	
	
	@Override
	protected void generate() 
	{
		int m_roomsize = 1000;
		int m_mindistance = 500;
		int volume = 100;
		Sample sample = getSample();
		int x = mRnd.nextInt(m_roomsize)-m_roomsize/2;
		int y = mRnd.nextInt(m_roomsize)-m_roomsize/2;
		
		// Distance to the left ear
		double distL = Math.sqrt(x*x+y*y)+m_mindistance;
		
		// Stereo Basis
		x -= 20;
		
		// Distance to the right ear
		double distR = Math.sqrt(x*x+y*y)+m_mindistance;
		int delaySamples = (int)((double)m_soundBuffer.sampleRate()*(distR-distL)/(33000));   
		
		if(mRnd.nextInt(16)< (mSeaGull/10))
		{
			// Left Channel at time m_time
			m_soundBuffer.insertSample(this, 0, mTime, sample,0,sample.sampleCount,(int)(volume*m_mindistance/distL));
		
			// Right Channel at time m_time+delaySamples. if delaySamples > 0: distR > distL => delay must be positive
			m_soundBuffer.insertSample(this, 1, mTime+delaySamples, sample,0,sample.sampleCount, (int)(volume*m_mindistance/distR));
		}
		mTime += sample.sampleCount*(mRnd.nextInt(3)+1);
	}
	
	protected Sample getSample()
	{
		int sampleIndex;
		Sample sample = null;
		
		do{
			// Select sample from the sample library
			sampleIndex = mRnd.nextInt(m_sampleLib.size());

			// Ensure the index is valid!
			sampleIndex = Math.max(Math.min(m_sampleLib.size()-1, sampleIndex),0);

			try{
				sample = m_sampleLib.get(sampleIndex);			
			}catch(IndexOutOfBoundsException ex){ }
			
		}while(sample == null);
		
		return sample;
	}

	public void setSeaGull(int seaGull) {
		mSeaGull = seaGull;
		m_soundBuffer.divisor = 10;
	}

	public int getSeaGull() {
		return mSeaGull;
	}
	
}
